package com.davfx.restream;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import com.davfx.httpnio.HttpResponse;

final class DatabaseProvider {

	private static final long MAX_SIZE = 10 * 1024 * 1024; // 10 Mib
	
	private final DatabaseFileAccessManager manager = new DatabaseFileAccessManager();
	
	public DatabaseProvider() {
	}
	
	private static final class InnerDatabaseReader implements DatabaseReader {
		private final DatabaseFileAccessManager manager;
		private final File dir;
		private DatabaseFileAccessManager.Access access;
		private long current;
		public InnerDatabaseReader(DatabaseFileAccessManager manager, String id, long from) {
			this.manager = manager;
			dir = manager.getDirectory(id);
			current = from;
			access = manager.find(dir, current);
		}
		
		private HttpResponse readHeader() throws IOException {
			int status = access.readInt();
			String reason = access.readString();
			int count = access.readInt();
			Map<String, String> headers = new HashMap<String, String>();
			for (int i = 0; i < count; i++) {
				String k = access.readString();
				String v = access.readString();
				headers.put(k, v);
			}
			return new HttpResponse(status, reason, headers);
		}
		
		@Override
		public boolean next() throws IOException {
			if (access != null) {
				if (access.eof()) {
					access.close();
					access = manager.find(dir, current + 1);
					if (access != null) {
						readHeader();
					}
				}
				current = access.readLong();
			}
			return (access != null);
		}
		
		@Override
		public long getTime() throws IOException {
			return current;
		}
		
		@Override
		public ByteBuffer getBuffer() throws IOException {
			return access.readBuffer();
		}
		
		@Override
		public HttpResponse getHttpResponse() throws IOException {
			if (access == null) {
				return null;
			}
			return readHeader();
		}
		@Override
		public void close() {
			access.close();
		}
	}
	
	private static final class InnerDatabaseWriter implements DatabaseWriter {
		private final DatabaseFileAccessManager manager;
		private final File dir;
		private DatabaseFileAccessManager.Access access;
		public InnerDatabaseWriter(DatabaseFileAccessManager manager, String id, long from) {
			this.manager = manager;
			dir = manager.getDirectory(id);
			access = manager.create(dir, from);
		}
		
		@Override
		public void setHttpResponse(HttpResponse response) throws IOException {
			access.writeInt(response.getStatus());
			access.writeString(response.getReason());
			Map<String, String> headers = response.getHeaders();
			access.writeInt(headers.size());
			for (Map.Entry<String, String> h : headers.entrySet()) {
				access.writeString(h.getKey());
				access.writeString(h.getValue());
			}
		}
		@Override
		public void write(long time, ByteBuffer buffer) throws IOException {
			access.writeLong(time);
			access.writeBuffer(buffer);
			if (access.getOffset() >= MAX_SIZE) {
				access.close();
				access = manager.create(dir, time);
			}
		}
		@Override
		public void close() {
			access.close();
		}
	}
	
	public Database get(final String id) {
		return new Database() {
			@Override
			public DatabaseReader getReader(final long from) {
				return new InnerDatabaseReader(manager, id, from);
			}
			
			@Override
			public DatabaseWriter getWriter(long from) {
				return new InnerDatabaseWriter(manager, id, from);
			}
		};
	}
}
